<?php

declare(strict_types=1);

namespace app\common\listener;

use think\Container;
use think\swoole\Websocket;
use \think\facade\Db;
use Swoole\Timer;
use think\swoole\websocket\Pusher;

class WebsocketTest
{
    public $websocket = null;
    public $company_id;
    public $tickId = [];
    public function __construct(Container  $container)
    {
        $this->websocket = $container->make(Websocket::class);
    }
    /**
     * 事件监听处理
     * @param $event
     */
    public function handle($event)
    {
        try {
            echo '接收到事件,' . $event->type . '---' . $event->data;
            echo '--------';
            // var_dump($event);
            $param = json_decode($event->data, true);
            // print_r($param);
            $this->company_id =  $param['company_id'];
            if ($event->type == 'default') {
                //  合伙人地图位置
                $this->mapLocation($event, $param);
                // 出入库数据
                $this->warehouseData($event,  $param);
                // 仓内概况
                $this->warehouseOverview($event, $param);
                // 销售数据
                $this->salesList($event, $param);
                // 经营数据
                $this->operateData($event, $param);
                // 仓库商品预警
                $this->whGoodsWarring($event, $param);
                // 门店订单
                $this->storeOrder($event, $param);
            }
        } catch (\Exception $e) {
            print_r($e->getMessage());
            //获取错误的行数 
            print_r($e->getLine());
        }
    }

    /**
     * 测试类型
     * @param $event
     */
    public function test($event)
    {
        $msg = json_encode($event->data, 256);
        $this->websocket->emit('callback', $msg);
    }

    /**
     * 合伙人地图位置
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \JsonException
     */
    public function mapLocation($frame, mixed $arr)
    {

        $company =  Db::table('vk_company');

        if ($arr['company_id']) {
            $map = $company->where('id', $arr['company_id']);
        } else {
            $map = $company->where('name', 'like', '%邓州%');
        }
        $company = $map->field('id,name,short_name,area_id,address,lng,lat')
            ->find();
        $company['title'] = $company['short_name'] . '商业体系运营管理平台';
        // var_dump( $company);

        // 从 vk_store 表中查询属于指定公司且状态为 1 的商店信息
        // 仅获取商店的 id, name, lon, lat 字段
        $store   =  Db::table('vk_store')->where([['company_id', '=', $company['id']], ['status', '=', 1]])
            ->field('id,name,lon,lat')
            ->select();

        // 从 vk_company_warehouse 表中查询属于指定公司且状态为 1 的仓库信息
        // 仅获取仓库的 id, name, lon, lat 字段
        $wh      =  Db::table('vk_company_warehouse')->where('company_id', $company['id'])->where('status', 1)
            ->field('id,name,lon,lat')
            ->select();

        $this->websocket->to($this->websocket->getSender())->emit('map', compact('company', 'store', 'wh'));
    }
    /**
     * 出入库数据
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function warehouseData($frame, mixed $arr): void
    {
        $report_goods_out_model   = Db::table('vk_report_goods_out');

        $data =  $report_goods_out_model->field('id,big_unit_out_num,middle_unit_out_num,small_unit_out_num,big_unit_out_value,middle_unit_out_value,small_unit_out_value')->select();
        $total_out_num = 0;
        $total_out_money = 0;

        foreach ($data    as $k => $v) {
            $total_out_num =  $v['big_unit_out_num'] + $v['middle_unit_out_num'] + $v['small_unit_out_num'];
            $total_out_money = sprintf("%.2f", $v['big_unit_out_value'] + $v['middle_unit_out_value'] + $v['small_unit_out_value']);
        }
        //采购入库
        $total_in_num = 0;
        $total_in_money = 0;
        $dealer_order = Db::table('vk_dealer_order');
        $dealer_order_data =  $dealer_order->where([['order_status', '=', 3]])->select()->toArray();

        foreach ($dealer_order_data as $k => $v) {

            // 初始化dealer_order_detail_model，用于操作vk_dealer_order_detail表
            $dealer_order_detail_model = Db::table('vk_dealer_order_detail');

            // 根据订单ID查询订单详情，包括已删除的记录，并将结果转换为数组
            $dealer_order_detail_data = $dealer_order_detail_model->where('dealer_order_id', $v['id'])->withTrashed()->select()->toArray();

            // 遍历订单详情数组，计算总入库数量和总入库金额
            foreach ($dealer_order_detail_data as $k2 => $v2) {
                // 累加每条订单详情中的商品数量到总入库数量
                $total_in_num += $v2['num'];
                // 累加每条订单详情中的采购总价到总入库金额
                $total_in_money += $v2['purchase_total_price'];
            }
        }

        //销退入库
        $company_order_model  = Db::table('vk_company_order');
        $company_order_data =  $company_order_model->where([['out_status', '=', 2]])->select()->toArray();

        foreach ($company_order_data as $k => $v) {
            $company_order_detail_model = Db::table('vk_company_order_detail');
            $company_order_data =  $company_order_detail_model->where([['company_order_id', '=', $v['id']]])->select()->toArray();
            foreach ($company_order_data as $k2 => $v2) {
                $total_in_num += $v2['num'];
                $total_in_money += $v2['total_price'];
            }
        }
        //调拨入库单
        $transfer_order_model = Db::table('vk_company_transfer_order');
        $transfer_order_dtata =  $transfer_order_model->where('company_id', $this->company_id)->where('check_status', 2)
            ->where('transfer_type', 2)->select()->toArray();


        foreach ($transfer_order_dtata as $k => $v) {

            // 初始化总入库数量和总入库金额变量
            $transfer_order_detail_model =  Db::table('vk_company_transfer_order_detail');
            $transfer_order_data =  $transfer_order_detail_model->where([['t_oid', '=', $v['id']]])->select()->toArray();

            // 遍历转让订单详情数据，计算总入库数量和总入库金额
            foreach ($transfer_order_data as $k2 => $v2) {
                // 累加每个订单详情的转让数量到总入库数量
                $total_in_num += $v2['transfer_num'];

                // 根据经销商商品规格ID获取对应的经销商商品规格信息
                $dealer_spec_model =  Db::table('vk_dealer_goods_spec');
                $dealer_spec_data =  $dealer_spec_model->where('id', $v2['dealer_goods_spec_id'])->find();

                // 计算每个订单详情的入库金额，并累加到总入库金额
                $total_in_money += $v2['transfer_num'] * $dealer_spec_data['purchase_price'];
            }
        }
        //今日入库订单量
        //采购入库订单
        $dealer_order_count =  $dealer_order->where([['order_status', '=', 3]])->whereTime('create_time', 'today')->count();
        $company_order_count =  $company_order_model->where([['out_status', '=', 2]])->whereTime('create_time', 'today')->count();
        $transfer_order_count =  $transfer_order_model->where('company_id', $this->company_id)->where('check_status', 2)->whereTime('create_time', 'today')
            ->where('transfer_type', 2)->count();

        //出库订单数量
        $out_num = $report_goods_out_model->field('id')->whereTime('time', 'today')->count();

        //总销售金额
        $sale_data = $company_order_model->where([['order_type', '=', 1], ['order_status', '=', 2]])->sum('order_amount');

        $store_model =  Db::table('vk_dealer_store');
        $driver_model =     Db::table('vk_driver');
        $deliver_count =  $driver_model->where('company_id', $this->company_id)->count();

        $warehouse_data = [
            // 总出库数量
            'total_out'       => $total_out_num,
            // 总出库金额
            'total_out_money' => $total_out_money,
            // 总入库数量
            'total_in'        => $total_in_num,
            // 总入库金额
            'total_in_money'  => $total_in_money,
            // 今日入库订单
            'today_in'        => $dealer_order_count + $company_order_count + $transfer_order_count,
            // 今日出库订单
            'today_out'       =>  $out_num,
            // 总销售金额
            'total_sales'     =>  $sale_data,
            // 总门店数
            'total_store'     => $store_model->count(),
            // 总车辆数
            'total_car'       => $deliver_count,
        ];


        $this->websocket->to($this->websocket->getSender())->emit('warehouse',  $warehouse_data);
    }

    /**
     * 仓库概览
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function warehouseOverview($frame, mixed $arr): void
    {

        // 获取仓库概览信息，仅包含状态为1（启用）且为顶级分类的记录
        $warehouse_overview = Db::table('vk_goods_cate')->where('status', 1)
            ->where('pid', 0)
            ->field('id,name')
            ->select()
            ->toArray();

        // 遍历每个仓库概览项，计算其下属分类的商品销售总额
        foreach ($warehouse_overview as $k => &$item) {
            // 获取当前分类的所有子分类ID
            $cate_ids = Db::table('vk_goods_cate')
                ->where('pid', $item['id'])
                ->column('id');

            // 初始化订单详情查询
            $order    =  Db::table('vk_dealer_order_detail');
            // 获取属于当前分类及其子分类的所有订单详情数据
            $order_detail_data =  $order->where('goods_cate_id', 'in', $cate_ids)->field('real_price,num')->select()->toArray();

            // 计算当前分类的销售总额
            $amount = 0;
            foreach ($order_detail_data as $k => $v) {
                $amount += $v['real_price'] * $v['num'];
            }

            // 将销售总额添加到当前分类项中
            $item['amount'] = $amount;
        }

        // 提取所有分类的销售总额，用于排序
        $amounts = array_column($warehouse_overview, 'amount');
        // 根据销售总额降序排列仓库概览数组
        array_multisort($amounts, SORT_DESC, $warehouse_overview);

        // 获取销售总额前7名的分类
        $data = array_slice($warehouse_overview, 0, 7);

        // 获取除前7名之外的其他分类
        $qita_arr = array_slice($warehouse_overview,  8);

        // 将其他分类的销售总额合并为一项，并添加到数据数组中
        array_push($data, ['name' => '其他', 'amount' => array_sum(array_column($qita_arr, 'amount'))]);

        $total_amount = array_sum(array_column($warehouse_overview, 'amount'));
        $this->websocket->to($this->websocket->getSender())->emit('warehouse_overview',  compact('data', 'total_amount'));
    }

    /**
     * 销售列表
     * @throws RandomException
     */
    public function salesList($frame, mixed $arr): void
    {
        $def_num     = 7;
        $list        = [];
        $create_time = [];
        if (isset($arr['create_time']) && !empty($arr['create_time'])) $create_time = $arr['create_time'];

        if (isset($create_time[0]) && isset($create_time[1])) {
            $time = $create_time[1];
            $num  = $this->difTime(strtotime($create_time[1]), strtotime($create_time[0]));
        } else {
            $time = date('Y-m-d');
            $num  = $def_num;
        }
        $company_order_model =  Db::table('vk_company_order');

        for ($i = 0; $i < $num + 1; $i++) {
            $date           = date('Y-m-d', strtotime('-' . $i . ' day', strtotime($time)));
            $start          = strtotime($date);
            $end            = strtotime($date) + 86400;
            $arr['date']    = $date;
            // 查询在指定时间范围内的公司订单数据，并且订单状态为2，订单类型为1
            $order_data = $company_order_model->whereBetween('create_time', [$start, $end])->where([['order_status', '=', 2], ['order_type', '=', 1]])
                ->select()->toArray();
            $amount = 0;
            foreach ($order_data as $k => $v) {
                // 初始化公司订单详情查询对象
                $company_order_detail =  Db::table('vk_company_order_detail');
                // 查询与当前订单ID匹配的订单详情中的总价格
                $total_price_arr =    $company_order_detail->where([['company_order_pid', '=', $v['id']]])->field('total_price')->select()->toArray();
                // 累加所有订单详情的总价格
                $amount         += array_sum($total_price_arr);
            }
            // 将计算出的总金额存入数组中
            $arr['amount'] = $amount;
            $list[]        = $arr;
        }

        $this->websocket->to($this->websocket->getSender())->emit('sales_list', $list);
    }

    /**
     * 经营数据
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \JsonException
     */
    public function operateData($frame, mixed $arr): void
    {
        $sql =  Db::table('vk_company');
        if (isset($arr['company_id'])) $sql = $sql->where('id', $arr['company_id']);
        $sql  = $sql->field('id,name');
        $list = $sql->select()->toArray();

        foreach ($list as $k => &$item) {
            // 采购数量
            $item['purchase_count'] = Db::table('vk_company_order')->where('company_id', $item['id'])
                ->where('order_status', 5)
                ->count();

            // 仓库数量
            $item['wh_count'] = Db::table('vk_company_warehouse')->where('company_id', $item['id'])
                ->count();

            // 库区数量
            $item['wh_area_count'] =  Db::table('vk_company_warehouse_area')->where('company_id', $item['id'])
                ->count();
            // 库位数量
            $item['wh_position_count'] =   Db::table('vk_company_warehouse_location')->where('company_id', $item['id'])
                ->count();
            // 车辆数量
            $item['car_count'] =  Db::table('vk_driver')->where('company_id', $item['id'])->count();
            // 在仓商品数量
            $goods_count = 0;
            $dealer_goods_data =  Db::table('vk_dealer_goods')->field('id')->where('company_id', $item['id'])->select()->toArray();

            // 遍历经销商商品数据，以计算总销售库存量
            foreach ($dealer_goods_data as $k => $v) {
                // 查询每个经销商商品的销售库存量并累加
                $dealer_goods_sales_stock = Db::table('vk_dealer_goods_spec')->where([['dealer_goods_id', '=', $v['id']]])->sum('sales_stock');
                $goods_count += $dealer_goods_sales_stock;
            }
            // 将计算的总销售库存量赋值给商品计数
            $item['goods_count'] = $goods_count;

            // 初始化销售数量为0，用于累加计算
            $sales_amount = 0;
            // 查询公司订单数据，以计算总销售数量
            $dealer_goods_data = Db::table('vk_company_order')->field('id')->where('company_id', $item['id'])->select()->toArray();
            foreach ($dealer_goods_data as $k => $v) {
                // 查询每个公司订单的销售数量并累加
                $num = Db::table('vk_company_order_detail')->where([['company_order_id', '=', $v['id']]])->sum('num');
                $sales_amount += $num;
            }
            // 总销数量
            $item['sales_amount'] =   $sales_amount;
        }

        $this->websocket->to($this->websocket->getSender())->emit('operate_data', $list);
    }
    // 仓库商品预警
    public function whGoodsWarring($frame, mixed $arr)
    {
        $def_num = 7;
        $list    = [];
        $time    = strtotime(date('Y-m-d')); // 获取当前时间的时间戳
        $sql     =  Db::table('vk_dealer_goods');

        // 当前预警数量
        $now_expired      = 0;
        /*$now_near_expired = $sql->where('expire_time', '<=', $time)
            ->where('expire_time', '>', $time - (60 * 24 * 3600))
            ->count();*/
        $now_near_expired  = 7;
        for ($i = 0; $i <= $def_num; $i++) {
            $date        = date('Y-m-d', strtotime('-' . $i . ' day', $time));
            $expire_time = $time - (60 * 24 * 3600); // 60天前的日期时间戳
            /*$num         = $sql->where('expire_time', '>=', $expire_time)
                ->where('expire_time', '<=', $time + (86400 * ($i + 1))) // 当前时间加上($i + 1)天
                ->count();*/
            $num = rand(1, 1000);
            $arr['date'] = $date;
            $arr['num']  = $num; // 这里假设我们总是需要真实数据
            $list[]      = $arr;
        }


        $this->websocket->to($this->websocket->getSender())->emit('wh_goods_warring',  compact('now_expired', 'now_near_expired', 'list'));
    }

    /**
     * 订单列表
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function storeOrder($frame, mixed $arr): void
    {
        // 获取订单列表
        $storeOrder = Db::table('vk_company_order')->where([['order_status', '=', 2]]);

        if (isset($arr['company_id'])) $storeOrder->where('company_id', $arr['company_id']);

        if (isset($arr['create_time']) && !empty($arr['create_time'])) $create_time = $arr['create_time'];

        if (isset($create_time[0]) && isset($create_time[1])) {
            $create_time[0] = strtotime($create_time[0]);
            $create_time[1] = strtotime($create_time[1]);
            $storeOrder->whereBetween('create_time', $create_time);
        }

        $list = $storeOrder->field('store_id,company_id,order_no,create_time')
            ->order('id', 'desc')
            ->select()->toArray();
        // print_r(  $list);
        foreach ($list as $k => &$item) {
            $item['create_time'] = date('Y-m-d H:i:s', $item['create_time']);
            $item['company_name'] = Db::table('vk_company')->where('id', $item['company_id'])->withTrashed()->field('name')
                ->value('name');
            $item['store_name']   = Db::table('vk_store')->where('id', $item['store_id'])->withTrashed()->field('name')
                ->value('name');
        }

        $this->websocket->to($this->websocket->getSender())->emit('store_order',  $list);
        // 定时推送
        $this->tickId[$this->websocket->getSender()] = Timer::tick(60000, function () use ($frame, $arr) {
            // 获取订单列表
            $storeOrder =  Db::table('vk_company_order')->where('order_status', 2);

            if (isset($arr['company_id'])) $storeOrder->where('company_id', $arr['company_id']);

            if (isset($arr['create_time']) && !empty($arr['create_time'])) $create_time = $arr['create_time'];

            if (isset($create_time[0]) && isset($create_time[1])) {
                $create_time[0] = strtotime($create_time[0]);
                $create_time[1] = strtotime($create_time[1]);
                $storeOrder->whereBetween('create_time', $create_time);
            }

            $list = $storeOrder->field('store_id,company_id,order_no,create_time')
                ->order('id', 'desc')
                ->select();
            foreach ($list as $k => &$item) {
                $item['create_time'] = date('Y-m-d H:i:s', $item['create_time']);
                $item['company_name'] = Db::table('vk_company')->where('id', $item['company_id'])->value('name');
                $item['store_name']   == Db::table('vk_store')->where('id', $item['store_id'])->value('name');
            }


            $this->websocket->to($this->websocket->getSender())->emit('store_order', $list);
        });
    }



    /**
     * 清除定时器
     * @param $server
     * @param $fd
     * @return void
     */
    public function delTickId($fd): void
    {
        if (isset($this->tickId[$fd])) {
            Timer::clear($this->tickId[$fd]);
        }
    }

    /**
     * 获取两个时间差(用于商品过期预警)
     * @param $created_time
     * @param int $start_time
     * @return false|int
     * @throws Exception
     */
    function difTime($created_time, int $start_time = 0): bool|int
    {
        if (0 == $created_time) {
            return 0;
        }
        $createdTime = new \DateTime(date("Ymd His", $created_time));
        // 获取当前时间
        if (0 == $start_time)   $now = new \DateTime();
        if (0 != $start_time)   $now = new \DateTime(date("Ymd His", $start_time));

        $diff = $now->diff($createdTime);

        return abs($diff->days);
    }
}
